/*
 * Copyright (C) 2009 Kristopher T Babic
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, see <http://www.gnu.org/licenses>.
 */

package edu.idp.shared.net;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Vector;

/**
 * @author Kristopher T Babic
 */
public class NetTransferObject {

    public static final char ERROR = (char) 0;
    public static final char OK = (char) 1;
    public static final char CMD_GET_UID = (char) 2;
    public static final char CMD_GET_ALL = (char) 3;
    public static final char CMD_GET_TIME = (char) 4;
    public static final char CMD_GET_NEW = (char) 5;
    public static final char CMD_ADD = (char) 6;
    public static final char CMD_CREATE = (char) 7;
    public static final char CMD_DATA = (char) 8;
    public static final char CMD_GET_IMAGES = (char) 9;
    public static final char CMD_REMOVE = (char) 10;

    private static final char MAX_CMD = (char) 9;
    private static final char MIN_CMD = (char) 0;

    private static final char INIT = '#';
    private static final String SEPERATOR = "#|";
    private static final String START = "#@";
    private static final String END = "#!";
    private static final String CMD = "#C";
    private static final String USER = "#U";
    private static final String DATA = "#D";
    private static final String IMAGE = "#I";
    private static final String REMOVE = "#R";
    private static final String TIME = "#T";

    public static final int MAX_LEN = 20;

    private Vector storedData = null;
    private Vector storedRemove = null;
    private String storedImageName = "";
    private String storedUID = "";
    private char storedCmd = java.lang.Character.MAX_VALUE;

    public NetTransferObject() {
    }
//  public NetTransferObject( String obj ) {}

    public String getUID() {
        return this.storedUID;
    }

    public String getImageName() {
        return this.storedImageName;
    }

    public char getCommand() {
        return this.storedCmd;
    }

    public Enumeration getData() {
        if (storedData == null || storedData.size() == 0)
            return null;
        return storedData.elements();
    }

    public Enumeration getRemovedData() {
        if (storedRemove == null || storedRemove.size() == 0)
            return null;
        return storedRemove.elements();
    }

    public void setUID(String uid) {
        if (uid == null)
            this.storedUID = "";
        else
            this.storedUID = uid;
    }

    public void setCommand(char cmd) {
        this.storedCmd = cmd;
    }

    public void setImageName(String image) {
        if (image == null)
            this.storedImageName = "";
        else
            this.storedImageName = image;
    }

    public void addData(String data) {
        if (data == null || data.equals(""))
            return;
        if (storedData == null)
            storedData = new Vector();
        storedData.addElement(data);
    }

    public void addRemove(String data) {
        if (data == null || data.equals(""))
            return;
        if (storedRemove == null)
            storedRemove = new Vector();
        storedRemove.addElement(data);
    }

    private String stuff(String in) {
        String out = "";

        for (int i = 0; i < in.length(); i++) {
            char tmp = in.charAt(i);
            if (tmp == INIT)
                out += tmp;
            out += tmp;
        }

        return out;
    }

    private String unstuff(String in) {
        boolean initFlag = false;
        String out = "";

        for (int i = 0; i < in.length(); i++) {
            char tmp = in.charAt(i);

            if (initFlag)
                initFlag = false;
            else {
                if (tmp == INIT)
                    initFlag = true;
                out += tmp;
            }
        }

        return out;
    }

    private String createCmd() {
        if (getCommand() != -1) {
            String s = "";
            s += getCommand();
            return stuff(s) + CMD;
        }
        else
            return "";
    }

    private String createImageName() {
        if (!(getImageName().equals("")))
            return stuff(getImageName()) + IMAGE;
        else
            return "";
    }

    private String createUID() {
        if (!(getUID().equals("")))
            return stuff(getUID()) + USER;
        else
            return "";
    }

    private String createData() {
        if (storedData == null || storedData.size() == 0)
            return "";

        String dataString = "";
        for (int i = 0; i < storedData.size(); i++) {
            if (i > 0)
                dataString += SEPERATOR;
            dataString += stuff((String) storedData.elementAt(i));
        }

        return stuff(dataString) + DATA;
    }

    private String createRemove() {
        if (storedRemove == null || storedRemove.size() == 0)
            return "";

        String dataString = "";
        for (int i = 0; i < storedRemove.size(); i++) {
            if (i > 0)
                dataString += SEPERATOR;
            dataString += stuff((String) storedRemove.elementAt(i));
        }

        return stuff(dataString) + REMOVE;
    }

    public void sendData(Socket s) throws Exception {
        if (s == null)
            throw (new Exception("Invalid socket"));
//////////
        s.setTcpNoDelay(true);
        sendData(s.getOutputStream());
    }

    public void sendData(OutputStream os) throws Exception {

        DataOutputStream out = new DataOutputStream(os);

//    out.writeChars(this.toString());
//    out.flush();
//System.out.print ("sending: ");
        String outString = this.toString();
        for (int i = 0; i < outString.length(); i++) {
//System.out.print ((int)outString.charAt(i)+" "); System.out.flush();
            out.writeChar(outString.charAt(i));
            out.flush();
        }
//    try { out.close(); } catch(Exception e) {}
    }

    public void readData(Socket s) throws Exception {
//    if (false)
//      throw(new Exception(""));
        s.setSoTimeout(30000);
//////////
        s.setTcpNoDelay(true);
        readData(s.getInputStream());
    }

    public void readData(InputStream is) throws Exception {

        reset();

        DataInputStream in = new DataInputStream(is);
        String input = "";
        //System.out.print("reading: ");
        int last = 0;
        int initCnt = 0;
        while (true) {
            char tmpChar;
            try {
                tmpChar = in.readChar();
//System.out.print(((int)tmpChar)+" ");
            }
            catch (EOFException e) {
                break;
            }

            input += tmpChar;
            if (tmpChar == '#') //{ System.out.print("#");
                initCnt++;        // }
            else {
                if (tmpChar == '!' && (initCnt % 2) != 0)
                    break;
                initCnt = 0;

            }
//System.out.flush();
/*
      int len = input.length();

      if (input.charAt(len-1) == INIT)
        initCnt++;

      int index = input.indexOf(END, last);

      if (index != -1) {
        if (len > 2) {
          if (index == len - 2 && (initCnt % 2) != 0) //input.charAt(len - 3) != NetTransport.INIT)
            break;
          else
            last = index+1;
        }
        else
        break;
      }

      if (input.charAt(len-1) != INIT)
        initCnt=0;
*/
        }
//System.out.println();
        parseInput(input);

//    if (this.storedData == null || this.storedData.size() == 0)
//      System.out.println("no data to retrieve");

//    for (int i = 0; i < input.length(); i++)
//      System.out.print((int)input.charAt(i)+" ");
//    System.out.println();
    }

    public void reset() {

        storedData = null;
        String storedImageName = "";
        String storedUID = "";
        storedCmd = (char) -1;

    }

    private void parseInput(String in) {
        if (in == null || in.length() == 0)
            return;

        int index = in.indexOf(START);

// this may be some kind of error, but i'm going to assume for now that it isn't
        if (index == -1) {
            index = 0;
            System.out.println("input string doesn't contain a Start delimeter");
        }
        else
            index += START.length();

        int i;// = index - 1;
        int start = index;
        int cntr = 0;
        for (i = index; i < (in.length() - 2); i++) {
            if (in.charAt(i) == INIT) {
                cntr++;
                if (cntr % 2 != 0) {
                    char delim[] = {in.charAt(i), in.charAt(i + 1)};
                    String tmpDelim = new String(delim);
//          if (tmpDelim.equals
//          if (isDelimeter(tmpDelim)) {
// SHOULD OPTIMIZE????//

                    if (tmpDelim.equals(CMD))
                        setCommand(unstuff(in.substring(start, i)).charAt(0));
                    else if (tmpDelim.equals(IMAGE))
                        setImageName(unstuff(in.substring(start, i)));
                    else if (tmpDelim.equals(USER))
                        setUID(unstuff(in.substring(start, i)));
                    else if (tmpDelim.equals(DATA))
                        parseData(unstuff(in.substring(start, i)));
                    else if (tmpDelim.equals(REMOVE))
                        parseRemoveData(unstuff(in.substring(start, i)));
                    else
                        continue;

                    i++;
                    start = i + 1;
                    continue;

                }
            }
            else {
                cntr = 0;
            }

        }
        //System.out.println(">"+s.substring(start,index));
        //System.out.println(">>"+unstuff(s.substring(start,index)));

//		return unstuff(s.substring(start, index));

    }

    private void parseData(String in) {

        if (in == null || in.length() == 0)
            return;

        int index = 0;

        int i;
        int start = index;
        int cntr = 0;
        int len = in.length();
        for (i = index; i < len; i++) {
//System.out.print(((int)in.charAt(i))+" ");
            if (in.charAt(i) == INIT) {
                cntr++;
                if (cntr % 2 != 0) {
                    char delim[] = {in.charAt(i), in.charAt(i + 1)};
                    String tmpDelim = new String(delim);
//          if (tmpDelim.equals
//          if (isDelimeter(tmpDelim)) {
// SHOULD OPTIMIZE????//

                    if (tmpDelim.equals(SEPERATOR))
                        addData(unstuff(in.substring(start, i)));
                    else
                        continue;

                    i++;
                    start = i + 1;
                    continue;

                }
            }
            else {
                cntr = 0;
                if (i == (len - 1)) {
                    addData(unstuff(in.substring(start, len)));
                }

            }

        }

    }

    private void parseRemoveData(String in) {

        if (in == null || in.length() == 0)
            return;

        int index = 0;

        int i;
        int start = index;
        int cntr = 0;
        int len = in.length();
        for (i = index; i < len; i++) {
            if (in.charAt(i) == INIT) {
                cntr++;
                if (cntr % 2 != 0) {
                    char delim[] = {in.charAt(i), in.charAt(i + 1)};
                    String tmpDelim = new String(delim);

                    // SHOULD OPTIMIZE????//

                    if (tmpDelim.equals(SEPERATOR))
                        addRemove(unstuff(in.substring(start, i)));
                    else
                        continue;

                    i++;
                    start = i + 1;
                    continue;

                }
            }
            else {
                cntr = 0;
                if (i == (len - 1)) {
                    addRemove(unstuff(in.substring(start, len)));
                }

            }

        }

    }

    private boolean isDelimeter(String in) {
        return (in.equals(CMD) ||
                in.equals(USER) ||
                in.equals(DATA) ||
                in.equals(REMOVE) ||
                in.equals(IMAGE));
/*
            in.equals(SEPERATOR) ||
            in.equals(TIME)      ||
            in.equals(END)       ||
 */
    }

    public String toString() {
        return START + createCmd()
                + createUID()
                + createImageName()
                + createData()
                + createRemove()
                + END;

    }

}